feat: support federated entities creation in sdk - #642
Conversation
|
Three issues found this run — inline comments posted for each. |
734646b to
9fac1c3
Compare
|
One new finding this run — inline comment posted. |
9fac1c3 to
ae989f2
Compare
|
Three findings this run — inline comments posted for each. 1. Integration test: wrong field name after SDK transform (line 1240) 2. 3. Raw numbers in |
ae989f2 to
b99532d
Compare
|
One new finding this run — inline comment posted. Misleading integration test description (line 1424) |
b99532d to
2dbc1db
Compare
|
Five new findings this run — inline comments posted for each. 1. Raw string 2. 3. 4. 5. |
2dbc1db to
6b46c22
Compare
|
Two new findings this run — inline comments posted for each. 1. Orphaned JSDoc block (src/services/data-fabric/entities.ts:860) 2. Raw string |
6b46c22 to
0899020
Compare
|
One new finding this run — inline comment posted. Missing
|
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
SearchabilityOperator, SearchabilityNamedSearch, and Searchability are publicly-exported types used only by the Federated feature (via EntityCreateExternalFieldMapping and ExternalFieldMapping.searchability). TypeDoc renders a page per interface, so each needs @experimental to carry the preview warning — matching the other Federated types. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
| * Compares two GUID strings case-insensitively. v3 endpoints return uppercase | ||
| * GUIDs while v1 and write operations return lowercase, so use this instead of | ||
| * strict equality when comparing record IDs across API versions. | ||
| */ |
There was a problem hiding this comment.
This will introduce breaking change. Should we transform the response to lowercase in SDK? CC: @vnaren23
There was a problem hiding this comment.
Can this be fixed from DF side? Is there any reason for v3 returning uppercase?
There was a problem hiding this comment.
Added a normalization so that sdk behavior remains consistent.
For DF side, will discuss with team, but sdk normalization should unblock
There was a problem hiding this comment.
Resolved: this is being fixed on the DF/backend side, not in the SDK.
One correction on direction — it is the reverse of the (now-removed) helper note: v1 returned the record Id uppercase; it is v3 that returns it lowercase. Reason: the v3 write/query/list responses wrap the record in EntityWriteResponseV3, which types Id as a System.Guid, and Newtonsoft serialises a Guid lowercase by default. v1 returned the raw DB string (uppercase). So it is an unintended side-effect of the typed envelope, not intentional — and it affects only the single insert/update, query, and list-read responses (batch and single-read return the raw uppercase string, so they are unchanged).
Plan (agreed with DF): the backend will hotfix the v3 response to emit the Id uppercase again (feature-flagged) early next week; the SDK will not normalise. I have dropped the SDK-side normalisation and removed this idsEqual helper — the integration tests now use strict ===, which pass once the hotfix lands. TS release follows the backend fix.
The API serializes directionType as a string ("ReadOnly"/"ReadAndWrite")
on both read and write (Newtonsoft StringEnumConverter; the entity API
host has used Newtonsoft since 2021). Numeric values were accepted on
write but every read came back as the string, so a numeric enum
mistyped the response and broke equality checks. Reverting to the string
values also matches released main, so it's non-breaking.
Verified end-to-end against alpha via the CLI + local SDK: federated
create, get, list, and records query all succeed and directionType
round-trips as "ReadOnly".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b162f49 to
fea7b79
Compare
|
Stale The Line 1439 still reads: A developer hovering over Fix — update line 1439 to match line 1075: |
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
0e347a0 to
0ea5f5b
Compare
|
Four findings this run — one new inline comment posted and three previously-resolved threads unresolved. 1. 2. 3. Unresolved: 4. Unresolved: error message missing 5. Unresolved: |
|
One new finding this run — inline comment posted. Stale The |
…round The v1->v3 record-Id casing mismatch (v3 EntityWriteResponseV3 serialises the Id lowercase, v1 returned uppercase) is being fixed at the source: the backend hotfixes the v3 response casing (feature-flagged). Per that decision the SDK does not normalise casing — the earlier SDK-side normalisation is dropped. Remove the case-insensitive idsEqual test helper and use strict Id equality in the integration tests; these pass once the backend hotfix returns the Id uppercase again. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0ea5f5b to
2c6228e
Compare
|
One new finding this run — inline comment posted. Invalid TypeScript syntax in
|
…ples - EntityMethods.update() @PARAM now lists the federated source/join deltas, matching EntityServiceModel.updateById() (the bound method accepts the same EntityUpdateByIdOptions, so the tooltip was under-documenting it). - @example placeholders `elementInstanceId: <elementInstanceId>` are not valid TypeScript (that parses as a type assertion); elementInstanceId is numeric, so use `0`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
…urceConnection Follow-on to #642. Adds two @experimental update deltas on EntityUpdateByIdOptions, both applied inside the existing full re-upsert (buildFederatedUpsertParts): - primarySource: make a source the primary. The backend derives the primary from the join topology (the source not on any join's right side), so this re-roots the joins onto the named source and clears the old primary's isPrimarySource flag (the backend only sets the new one, never clears the old). Guards against re-rooting a 3+ source entity into a chain the backend would otherwise accept and store silently. - updateSourceConnection: swap a connector source's connection, keeping its fields and joins and re-pointing the source's joins at the new connection id. Rejects a native source and a connector-key mismatch. Also makes every source-referencing delta identify a source by BOTH sourceObjectName and sourceConnectionId (a connector connectionId, or the entityId for a native source). A federated entity may legitimately have two sources with the same object name on different connections (the backend keys sources by (connectionId, objectName)), so an object name alone is ambiguous. Affected: addFieldsToSource, removeFieldsFromSource, updateExternalFieldMapping, updateSourceJoin (+relatedSourceConnectionId), removeExternalSources (now {sourceObjectName, sourceConnectionId}[]), primarySource, updateSourceConnection. Shared FederatedSourceRef type; findSource matches on both. Updates the updateById JSDoc examples/prose and adds integration it.todo entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…urceConnection Follow-on to #642. Adds two @experimental update deltas on EntityUpdateByIdOptions, both applied inside the existing full re-upsert (buildFederatedUpsertParts): - primarySource: make a source the primary. The backend derives the primary from the join topology (the source not on any join's right side), so this re-roots the joins onto the named source and clears the old primary's isPrimarySource flag (the backend only sets the new one, never clears the old). Guards against re-rooting a 3+ source entity into a chain the backend would otherwise accept and store silently. - updateSourceConnection: swap a connector source's connection, keeping its fields and joins and re-pointing the source's joins at the new connection id. Rejects a native source and a connector-key mismatch. Also makes every source-referencing delta identify a source by BOTH sourceObjectName and sourceConnectionId (a connector connectionId, or the entityId for a native source). A federated entity may legitimately have two sources with the same object name on different connections (the backend keys sources by (connectionId, objectName)), so an object name alone is ambiguous. Affected: addFieldsToSource, removeFieldsFromSource, updateExternalFieldMapping, updateSourceJoin (+relatedSourceConnectionId), removeExternalSources (now {sourceObjectName, sourceConnectionId}[]), primarySource, updateSourceConnection. Shared FederatedSourceRef type; findSource matches on both. Updates the updateById JSDoc examples/prose and adds integration it.todo entries. Also fixes the by-name updateRecord/updateRecords integration tests: they updated writableFields[0] with generateFieldValue, which has no choiceset case and falls back to a string; when the shared entity's first writable field resolves to an integer choiceset the backend rejects it. p_GetFieldsByEntityId has no ORDER BY, so field order is query-plan-dependent — a plan flip on alpha (Sep 26-28) made the choiceset field first on every branch. Mirror the choiceset-skip the by-id update tests apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…urceConnection Follow-on to #642. Adds two @experimental update deltas on EntityUpdateByIdOptions, both applied inside the existing full re-upsert (buildFederatedUpsertParts): - primarySource: make a source the primary. The backend derives the primary from the join topology (the source not on any join's right side), so this re-roots the joins onto the named source and clears the old primary's isPrimarySource flag (the backend only sets the new one, never clears the old). Guards against re-rooting a 3+ source entity into a chain the backend would otherwise accept and store silently. - updateSourceConnection: swap a connector source's connection, keeping its fields and joins and re-pointing the source's joins at the new connection id. Rejects a native source and a connector-key mismatch. Also makes every source-referencing delta identify a source by BOTH sourceObjectName and sourceConnectionId (a connector connectionId, or the entityId for a native source). A federated entity may legitimately have two sources with the same object name on different connections (the backend keys sources by (connectionId, objectName)), so an object name alone is ambiguous. Affected: addFieldsToSource, removeFieldsFromSource, updateExternalFieldMapping, updateSourceJoin (+relatedSourceConnectionId), removeExternalSources (now {sourceObjectName, sourceConnectionId}[]), primarySource, updateSourceConnection. Shared FederatedSourceRef type; findSource matches on both. Updates the updateById JSDoc examples/prose and adds integration it.todo entries. Also fixes the by-name updateRecord/updateRecords integration tests: they updated writableFields[0] with generateFieldValue, which has no choiceset case and falls back to a string; when the shared entity's first writable field resolves to an integer choiceset the backend rejects it. p_GetFieldsByEntityId has no ORDER BY, so field order is query-plan-dependent — a plan flip on alpha (Sep 26-28) made the choiceset field first on every branch. Mirror the choiceset-skip the by-id update tests apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…urceConnection Follow-on to #642. Adds two @experimental update deltas on EntityUpdateByIdOptions, both applied inside the existing full re-upsert (buildFederatedUpsertParts): - primarySource: make a source the primary. The backend derives the primary from the join topology (the source not on any join's right side), so this re-roots the joins onto the named source and clears the old primary's isPrimarySource flag (the backend only sets the new one, never clears the old). Guards against re-rooting a 3+ source entity into a chain the backend would otherwise accept and store silently. - updateSourceConnection: swap a connector source's connection, keeping its fields and joins and re-pointing the source's joins at the new connection id. Rejects a native source and a connector-key mismatch. Also makes every source-referencing delta identify a source by BOTH sourceObjectName and sourceConnectionId (a connector connectionId, or the entityId for a native source). A federated entity may legitimately have two sources with the same object name on different connections (the backend keys sources by (connectionId, objectName)), so an object name alone is ambiguous. Affected: addFieldsToSource, removeFieldsFromSource, updateExternalFieldMapping, updateSourceJoin (+relatedSourceConnectionId), removeExternalSources (now {sourceObjectName, sourceConnectionId}[]), primarySource, updateSourceConnection. Shared FederatedSourceRef type; findSource matches on both. Updates the updateById JSDoc examples/prose and adds integration it.todo entries. Also fixes the by-name updateRecord/updateRecords integration tests: they updated writableFields[0] with generateFieldValue, which has no choiceset case and falls back to a string; when the shared entity's first writable field resolves to an integer choiceset the backend rejects it. p_GetFieldsByEntityId has no ORDER BY, so field order is query-plan-dependent — a plan flip on alpha (Sep 26-28) made the choiceset field first on every branch. Mirror the choiceset-skip the by-id update tests apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ateExternalConnection Follow-on to #642. Adds federated source and join deltas to EntityUpdateByIdOptions (all @experimental). They are applied inside the existing full re-upsert (buildFederatedUpsertParts): - addExternalSources / removeExternalSources - addExternalFields / removeExternalFields (fieldNames are the entity's column names) - addSourceJoins: connect a source added in the same call - updateSourceJoin: change only the join fields of an existing join - replaceSourceJoins: set the complete join set. This is how the primary source changes, because the backend derives the primary from the joins (the source every join starts from). A join can't be removed on its own, so there is no removeSourceJoins. It can't be combined with addSourceJoins or updateSourceJoin. - updateExternalConnection: point a connector source at another connection, keeping its object, fields and joins and re-pointing the joins at the new connection id. Native sources are rejected. Every delta that names an existing source identifies it by BOTH sourceObjectName and sourceConnectionId (a connector connectionId, or the entityId for a native source), because an entity can have two sources with the same object name on different connections. Shared FederatedSourceRef type. The SDK does not repeat validation the backend already does (join graph, duplicate sources, empty sources, duplicate field names). Also fixes the join cascade on removeExternalFields: joins refer to external field names, so the removed columns are mapped to their external names before joins are dropped. JSDoc on every option explains what it does and how the deltas fit together. Adds unit tests for each delta and integration tests (gated on the DF_FED_* env vars) for adding a native source with its join, changing the primary, cascading a source removal and swapping a connection. Also fixes the by-name updateRecord/updateRecords integration tests: they updated writableFields[0] with generateFieldValue, which has no choiceset case and falls back to a string; when the shared entity's first writable field resolves to an integer choiceset the backend rejects it. p_GetFieldsByEntityId has no ORDER BY, so field order is query-plan-dependent — a plan flip on alpha (Sep 26-28) made the choiceset field first on every branch. Mirror the choiceset-skip the by-id update tests apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds federated Data Fabric entity support to the SDK, on top of the v3 API migration.
What's in here
1. Migrate entity operations to the v3 API (DS-8953) — record CRUD and schema create/update/metadata move to
/api/v3/entities/.... Mostly endpoint-path swaps + request/response type alignment; request bodies, pagination, and batch responses are unchanged.GET_ALLstays on v1 (v3 has no tenant-only listing);getAll()routesfolderKey/includeFolderEntitiesto v3.2. Federated entity create, update, and query.
createacceptsentityClass: FederatedwithexternalFields(external-connector or native source + object detail + field mappings) and optionalsourceJoinConditionDetails.updateByIdgains federated source/join deltas:addExternalSources,removeExternalSources(cascades the removed source's joins),addFieldsToSource,removeFieldsFromSource,updateExternalFieldMapping,addSourceJoins,updateSourceJoin. The v3 API is a full-definition upsert, so the SDK reads the current definition, merges the delta, and reposts the whole thing.queryRecordsByIdnow routes to the v3 query endpoint (/api/v3/entities/entity/{id}/query) for every join-less query. This is what lets federated entities be queried — the legacy v1 by-id endpoint blocks them (Cannot access Federated entity …). Queries with multi-entityjoinsstill route to the v1 by-name endpoint (the only one that executes joins).Notes for reviewers (found validating live against the v3 API)
fields(isExternalField=true) as well as underexternalFields; carrying those intofieldson the repost duplicates them and the upsert fails — the native carry-forward excludesisExternalField.fieldDisplayTypebut the upsert requires it → defaulted to"Basic"(a missing one surfaces as a misleading join-dependency error, not a clear validation error).sourceJoinCriterias(object/field IDs) are translated to write-shapesourceJoinConditionDetails(object names + connection ids).joinTypepasses through (string"LeftJoin"accepted);entityClassmaps toentityClassId.Verification
npm run test:unit); typecheck + lint clean.Version
Preview version bumped to
1.6.1-entities3(published). A formal release version bump remains a separate step per the repo release workflow.🤖 Generated with Claude Code